package com.adjaisd.scarecrow.service.impl;

import com.adjaisd.scarecrow.dto.QuotaCount;
import com.adjaisd.scarecrow.dto.QuotaInfo;
import com.adjaisd.scarecrow.dto.QuotaTrend;
import com.adjaisd.scarecrow.entity.Device;
import com.adjaisd.scarecrow.entity.Panel;
import com.adjaisd.scarecrow.entity.Quota;
import com.adjaisd.scarecrow.mapper.PanelMapper;
import com.adjaisd.scarecrow.repo.TimeSeriesRepository;
import com.adjaisd.scarecrow.service.DeviceService;
import com.adjaisd.scarecrow.service.DeviceStatusService;
import com.adjaisd.scarecrow.service.PanelService;
import com.adjaisd.scarecrow.service.QuotaService;
import com.adjaisd.scarecrow.vo.DeviceStatusVO;
import com.adjaisd.scarecrow.vo.Pager;
import com.adjaisd.scarecrow.vo.QuotaDataVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author adjaisd
 * @since 2022-04-23
 */
@Service
public class PanelServiceImpl extends ServiceImpl<PanelMapper, Panel> implements PanelService {

    @Autowired
    PanelMapper panelMapper;

    @Override
    public Panel getPanel(Long userId, String name, Long deviceId, Long quotaId) {
        QueryWrapper<Panel> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Panel::getUserId, userId)
                .eq(Panel::getName, name)
                .eq(Panel::getDeviceId, deviceId)
                .eq(Panel::getQuotaId, quotaId);
        List<Panel> panelList = this.list(wrapper);
        if (panelList.size() > 0) return panelList.get(0);
        else return null;
    }

    @Override
    public boolean addPanel(Panel panel) {
        return panelMapper.insert(panel) > 0;
    }

    @Override
    public boolean delPanel(Long userId, String name, Long deviceId, Long quotaId) {
        Panel panel = getPanel(userId, name, deviceId, quotaId);
        if (panel == null) return false;
        panel.setCreateDate(0L);
        return panelMapper.updateById(panel) > 0;
    }

    @Autowired
    DeviceStatusService deviceStatusService;

    @Override
    public Pager<Device> getDevicePage(Long userId, Long page, Long pageSize, String number) {
        Pager<DeviceStatusVO> pager = deviceStatusService.queryPage(userId, page, pageSize, number, "", -1);

        LinkedList<Device> deviceList = new LinkedList<>();
        for (DeviceStatusVO deviceStatusVO : pager.getItems()) {
            Device device = new Device();
            BeanUtils.copyProperties(deviceStatusVO, device);
            deviceList.add(device);
        }
        Pager<Device> pageResult = new Pager<>(pager.getCounts(), pageSize);
        pageResult.setItems(deviceList);
        return pageResult;
    }

    @Autowired
    TimeSeriesRepository timeSeriesRepository;

    @Autowired
    QuotaService quotaService;

    @Override
    public Pager<Quota> getQuotaPage(Long userId, Long page, Long pageSize, String deviceId) {
        String fromQl = " from ( select quotaId,value from quota where deviceId='" + deviceId + "' group by deviceId,quotaId  ) ";
        String listQl = "select distinct(quotaId ) as quotaId " + fromQl + " limit " + pageSize + " offset " + (page - 1) * pageSize;
        String countQl = " select count( distinct(quotaId )) as count " + fromQl;
        List<QuotaInfo> quotaInfoList = timeSeriesRepository.query(listQl, QuotaInfo.class);

        //从influx中得到指标id列表
        List<String> quotaIdList = quotaInfoList.stream().map(QuotaInfo::getQuotaId).collect(Collectors.toList());
        //统计记录个数
        List<QuotaCount> quotaCountList = timeSeriesRepository.query(countQl, QuotaCount.class);

        if (quotaCountList == null || quotaCountList.size() == 0) {
            Pager<Quota> pager = new Pager<>(0L, 0L);
            pager.setItems(Lists.newArrayList());
            return pager;
        }
        LinkedList<Quota> quotaList = new LinkedList<>();
        for (String quotaId : quotaIdList) {
            Quota quota = quotaService.getById(quotaId);
            quotaList.add(quota);
        }
        Long count = quotaCountList.get(0).getCount();
        Pager<Quota> pager = new Pager<>(count, pageSize);
        pager.setItems(quotaList);
        return pager;
    }

    @Override
    public List<QuotaTrend> getQuotaTrendList(String beg, String end, String quotaId, String deviceId, int type) {
        StringBuilder ql = new StringBuilder("select first(value) as pointValue from quota ");
        ql.append("where time>='" + beg + "' and time<='" + end + "' ");
        ql.append("and quotaId='" + quotaId + "' ");
        ql.append("and deviceId='" + deviceId + "' ");
        // 时间间隔
        if (type == 1) // 1分钟
            ql.append("group by time(1m)");
        if (type == 2) // 1小时
            ql.append("group by time(1h)");
        if (type == 3) // 1天
            ql.append("group by time(1d)");
        List<QuotaTrend> quotaTrendList = timeSeriesRepository.query(ql.toString(), QuotaTrend.class);
        return fill(quotaTrendList);
    }

    @Autowired
    DeviceService deviceService;

    // userId,quotaId必定存在
    @Override
    public List<QuotaDataVO> getQuotaDataList(Long userId, String deviceId, String quotaId, String beg, String end, int type) {
        // 根据设备ID或指标ID获取数据
        LinkedList<Long> quotaIdList = new LinkedList<>();
        if (!Strings.isNullOrEmpty(quotaId)) {   // 存在指标ID
            quotaIdList.add(Long.valueOf(quotaId));
        } else if (!Strings.isNullOrEmpty(deviceId)) { // 存在设备ID
            Device device = deviceService.getDeviceByID(Long.valueOf(deviceId));
            QueryWrapper<Quota> wrapper = new QueryWrapper<>();
            wrapper.lambda().gt(Quota::getCreateTime, 0L)
                    .eq(Quota::getNumber, device.getNumber())
                    .eq(Quota::getOwnerId, userId);
            List<Quota> quotaList = quotaService.list(wrapper);
            List<Long> list = quotaList.stream().map(Quota::getId).collect(Collectors.toList());
            quotaIdList.addAll(list);
        }
        List<QuotaDataVO> list = new LinkedList<>();
        for (Long qId : quotaIdList) {
            Quota quota = quotaService.getById(qId);
            List<QuotaTrend> trendList = getQuotaTrendList(beg, end, qId + "", deviceId, type);
            QuotaDataVO quotaDataVO = new QuotaDataVO();
            BeanUtils.copyProperties(quota, quotaDataVO);
            quotaDataVO.setQuotaId(qId + "");
            quotaDataVO.setDeviceId(deviceId);
            LinkedList<String> xdata = new LinkedList<>();
            LinkedList<Double> series = new LinkedList<>();
            trendList.forEach(t -> {
                xdata.add(formatTime(t.getTime(), type));
                series.add(t.getPointValue());
            });
            quotaDataVO.setXData(xdata);
            quotaDataVO.setData(series);
            list.add(quotaDataVO);
        }
        return list;
    }


    // 填充数据
    private List<QuotaTrend> fill(List<QuotaTrend> quotaTrendList) {
        Double previousValue = null;// 上一个值
        for (QuotaTrend quotaTrend : quotaTrendList) {
            if (quotaTrend.getPointValue() != null) {
                previousValue = quotaTrend.getPointValue();
                break;
            }
        }
        if (previousValue == null) previousValue = 0d;
        //数据填充逻辑
        for (QuotaTrend quotaTrend : quotaTrendList) {
            if (quotaTrend.getPointValue() == null)
                quotaTrend.setPointValue(previousValue);
            else previousValue = quotaTrend.getPointValue();
        }
        return quotaTrendList;
    }

    private String formatTime(String time, int type) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        if (type == 1) return localDateTime.getMinute() + "";
        else if (type == 2) return localDateTime.getHour() + "";
        else if (type == 3) return localDateTime.getMonthValue() + "月" + localDateTime.getDayOfMonth() + "日";
        else return time;
    }

}
